﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using haptic.src.engine.debug;
using haptic.src.engine.render;

namespace haptic.src.engine.animation
{
    public class AutomateInstance
    {
        public class Context
        {
            public Vector2 m_vPosition = Vector2.Zero;
            public Vector2 m_vFacingDirection = Vector2.UnitX;
        }
        #region Constructors
        public AutomateInstance(Automate oAutomate)
        {
            m_oAutomate = oAutomate;

            // Default state
            State oDefaultState = m_oAutomate.GetDefaultState();
            if (oDefaultState != null)
            {
                m_oDefaultState = CreateStateInstance(oDefaultState.m_sName);
                m_sNextFrameState = oDefaultState.m_sName;
            }

            m_oCurrentState = m_oDefaultState;
        }
        #endregion

        #region Edit
        public void SetEnterCallback(string sStateName, StateInstance.CbOnEnter cbEnter)
        {
            if (cbEnter != null)
                m_oOnStateEnterCallbacks.Add(sStateName, cbEnter);
            else
                m_oOnStateEnterCallbacks.Remove(sStateName);
        }
        #endregion

        #region Update
        public void ChangeState(string sNextState)
        {
            State oState = m_oAutomate.GetState(sNextState);
            if (oState != null)
                m_sNextFrameState = sNextState;
            else if (m_oAutomate.GetDefaultState() != null)
            {
                m_sNextFrameState = m_oAutomate.GetDefaultState().m_sName;
                Log.Error("Unknown '" + sNextState + "' automate state in '" + m_oAutomate.sFilePath + "'");
            }
        }
        public void ChangeStateToDefault()
        {
            if (m_oDefaultState != null)
                m_sNextFrameState = m_oDefaultState.oState.m_sName;
        }
        private StateInstance CreateStateInstance(string sStateName)
        {
            State oState = m_oAutomate.GetState(sStateName);
            if (oState == null)
                return null;

            StateInstance oStateInst = oState.CreateInstance();
            if (oStateInst == null)
                return null;

            oStateInst.m_cbOnEnter = (StateInstance.CbOnEnter)m_oOnStateEnterCallbacks[sStateName];
            oStateInst.m_cbOnUpdate = (StateInstance.CbOnUpdate)m_oOnStateUpdateCallbacks[sStateName];
            oStateInst.m_cbOnExit = (StateInstance.CbOnExit)m_oOnStateExitCallbacks[sStateName];

            return oStateInst;
        }
        public void Update(GameTime oTime)
        {
            if (m_oCurrentState == null || m_sNextFrameState != m_oCurrentState.oState.m_sName)
            {
                if (m_oCurrentState != null)
                    m_oCurrentState.Exit();
                m_oCurrentState = CreateStateInstance(m_sNextFrameState);
                if (m_oCurrentState == null)
                    ChangeStateToDefault();
                if (m_oCurrentState != null)
                    m_oCurrentState.Enter();
            }

            if (m_oCurrentState != null)
            {
                m_oCurrentState.Update(oTime, m_oContext);
            }
        }
        #endregion

        #region Draw
        public void Draw(Renderer oRenderer)
        {
            if (m_oCurrentState != null)
            {
                m_oCurrentState.Draw(oRenderer, m_oContext);
            }
        }
        #endregion

        #region Accessors
        public bool IsCurrentState(string sStateName)
        {
            if (m_oCurrentState == null)
                return false;
            else
                return m_oCurrentState.oState.m_sName == sStateName;
        }
        #endregion

        #region Attributes
        private Hashtable m_oOnStateEnterCallbacks = new Hashtable();
        private Hashtable m_oOnStateUpdateCallbacks = new Hashtable();
        private Hashtable m_oOnStateExitCallbacks = new Hashtable();
        public string m_sNextFrameState;
        private Automate m_oAutomate;
        private StateInstance m_oCurrentState;
        private StateInstance m_oDefaultState;
        public Automate oAutomate { get { return m_oAutomate; } }
        public Context m_oContext = new Context();
        #endregion
    }
}
